﻿using System;
using Tiny.Imaging.Filter.PixelLibrary;

namespace Tiny.Imaging.Filter.PointFilter
{
    /// 1) RGB -> YIQ:
    ///	Y = 0.299 * R + 0.587 * G + 0.114 * B
    ///	I = 0.596 * R - 0.274 * G - 0.322 * B
    ///	Q = 0.212 * R - 0.523 * G + 0.311 * B
    ///	
    /// 2) update:
    ///	I = 51
    ///	Q = 0
    ///	
    ///	3) YIQ -> RGB:
    ///	R = 1.0 * Y + 0.956 * I + 0.621 * Q
    ///	G = 1.0 * Y - 0.272 * I - 0.647 * Q
    ///	B = 1.0 * Y - 1.105 * I + 1.702 * Q
    public class SepiaFilter : BaseFilter.BaseFilter
    {
        private readonly float[][] _factor;

        public SepiaFilter(float sepiaFactor = 1.0f, Func<int, int, int> blend = null, int opacity = 100)
            : base(blend, opacity)
        {
            sepiaFactor = sepiaFactor / 100.0f;
            _factor = new float[3][];
            _factor[0] = new float[3];
            _factor[0][0] = 1 - (0.607f * sepiaFactor);
            _factor[0][1] = 0.769f * sepiaFactor;
            _factor[0][2] = 0.189f * sepiaFactor;
            _factor[1] = new float[3];
            _factor[1][0] = 0.349f * sepiaFactor;
            _factor[1][1] = 1 - (0.314f * sepiaFactor);
            _factor[1][2] = 0.168f * sepiaFactor;
            _factor[2] = new float[3];
            _factor[2][0] = 0.272f * sepiaFactor;
            _factor[2][1] = 0.534f * sepiaFactor;
            _factor[2][2] = 1 - (0.869f * sepiaFactor);
        }

        public override int Process(Rgba rgba)
        {
            Rgba result = new Rgba
                              {
                                  R =
                                      MathLibrary.MathLibrary.Clamp(((rgba.R * _factor[0][0]) + (rgba.G * _factor[0][1]) +
                                                                     (rgba.B * _factor[0][2]))),
                                  G =
                                      MathLibrary.MathLibrary.Clamp(((rgba.R * _factor[1][0]) + (rgba.G * _factor[1][1]) +
                                                                     (rgba.B * _factor[1][2]))),
                                  B =
                                      MathLibrary.MathLibrary.Clamp(((rgba.R * _factor[2][0]) + (rgba.G * _factor[2][1]) +
                                                                     (rgba.B * _factor[2][2])))
                              };

            return BlendRgba(rgba, result).ToInteger();
        }
    }
}